package hc.bre
import org.slf4j.*
import hc.Util
import hc.bre.calc.scorecard.ScorecardDefinition
import hc.bre.call.SqlQueryDefinition
import hc.bre.clas.abtest.AbtestDefinition
import hc.bre.clas.branch.BranchDefinition
import hc.bre.clas.range.RangeDefinition
import hc.bre.clas.yesno.YesNoDefinition
import hc.bre.data.encoder.EncoderDefinition
import hc.bre.data.setting.SettingDefinition
import hc.bre.data.strategy.StrategyDefinition
import hc.bre.deci.tree.TreeDefinition
import hc.bre.flow.FlowDefinition
import hc.bre.func.FunctionDefinition
import hc.bre.policy.CategoryDefinition
import hc.bre.policy.ReasonDefinition
import hc.bre.policy.CheckDefinition
import hc.bre.project.ProjectDefinition
import hc.bre.script.ClosureDefinition
import hc.bre.variable.VariableDefinition
import java.lang.reflect.Field

@groovy.transform.CompileStatic
@groovy.transform.ToString(includeNames=true, includePackage = false)
class ComponentRegistry {
	private static final Logger _log = LoggerFactory.getLogger(ComponentRegistry.class);

	static List<ComponentConfig> componentList =[];
	
	//rtype to ComponentConfig
	static Map<String,ComponentConfig> componentMap = new HashMap<String,ComponentConfig>();
	static Map<Class,ComponentConfig> componentClassMap = new HashMap<Class,ComponentConfig>();

	static Object getConfig() {
		def map =
				[
					componentList:componentList,
					componentMap:componentMap,
				];

		return map;
	}

	static ComponentConfig get(String rtype) {
		def ret  = componentMap.get(rtype);

		if(ret == null) {
			_log.error("The component definition of '{}' is not found.",rtype)
		}

		return ret;
	}
	static ComponentConfig get(Class clazz) {
		def ret  = componentClassMap.get(clazz);

		if(ret == null) {
			_log.error("The component definition of '{}' is not found.",clazz)
		}
		return ret;
	}

	static register(Class clazz) {
		Field field = hc.Util.getStaticField(clazz,"_config");
		if(field) {
			ComponentConfig config = field.get(clazz) as ComponentConfig ;
			if(config) {
				config.ruleClass = clazz;
				componentList.add(config);
				return;
			}
		}

		throw new Exception('failed to register the rule of '+ clazz.getName());
	}

	static {
		register(VariableDefinition.class);
		register(RangeDefinition.class);
		register(YesNoDefinition.class);
		register(BranchDefinition.class);
		register(AbtestDefinition.class);
		
		register(SqlQueryDefinition.class);
		register(EncoderDefinition.class);
		register(SettingDefinition.class);
		register(ScorecardDefinition.class);
		register(TreeDefinition.class);
		register(CategoryDefinition.class);
		register(ReasonDefinition.class);
		register(CheckDefinition.class);
		register(StrategyDefinition.class);
		register(FlowDefinition.class);
		register(FunctionDefinition.class);
		register(ClosureDefinition.class);
		register(ProjectDefinition.class);
	}

	static {
		componentList.each {
			componentMap.put(it.rtype, it);
			componentClassMap.put(it.ruleClass, it);
		};
	}
}
